﻿#include "stdafx.h"
#if _QG_USE_D11
#include "qg_d11_dev.h"
#include "qg_d11_mtrl.h"
#include "qg_d11_cnv.h"
#include "qg_trace.h"
#include "qg_math.h"

// 스크린삿
qgImage* D11Device::ScreenCapture()
{
	HRESULT hr;

	// 스왑 체인 텍스쳐
	ID3D11Texture2D* scr;
	if (FAILED(hr = _render._sc->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&scr)))
		return NULL;

	D3D11_TEXTURE2D_DESC std;
	scr->GetDesc(&std);

	// 멀티 샘플링 죽임... 죽이자... 이놈 땜에 날라간 4시간이여!!!!
	if (std.SampleDesc.Count > 1)
	{
		D3D11_TEXTURE2D_DESC rtd =
		{
			std.Width, std.Height, 1, 1, std.Format, {1, 0},
			D3D11_USAGE_DEFAULT, 0, 0, std.MiscFlags
		};

		ID3D11Texture2D* rtx;
		if (FAILED(hr = _device->CreateTexture2D(&rtd, NULL, &rtx)))
		{
			scr->Release();
			return NULL;
		}

		// 이놈은 성공하던 안하던 뭐... 실패시 검은색으로...
		_context->ResolveSubresource(rtx, 0, scr, 0, std.Format);

		scr->Release();
		scr = rtx;
	}

	// STAGING 텍스쳐로 복사
	D3D11_TEXTURE2D_DESC ttd =
	{
		std.Width, std.Height, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, {1, 0},
		D3D11_USAGE_STAGING, 0, D3D11_CPU_ACCESS_READ, 0
	};

	ID3D11Texture2D* tex;
	if (FAILED(hr = _device->CreateTexture2D(&ttd, NULL, &tex)))
	{
		scr->Release();
		return NULL;
	}

	// 마찬가지로 실패시 검은색
	_context->CopyResource(tex, scr);

	// 비트맵 준비
	qgImage* img;
	kint pitch = std.Width * sizeof(kint);
	kint size = std.Height * pitch;
	kbyte* data = k_new(size, kbyte);

	// 잠그고 복사
	D3D11_MAPPED_SUBRESOURCE ms;
	if (FAILED(hr = _context->Map(tex, 0, D3D11_MAP_READ, 0, &ms)))
		img = NULL;
	else
	{
		if (pitch == (kint)ms.RowPitch)
			memcpy(data, ms.pData, size);
		else
		{
			// 모든 경우에 RowPitch가 pitch보다 더 크다
			kbyte* src = (kbyte*)ms.pData;
			kbyte* dst = (kbyte*)data;

			for (UINT y = 0; y < std.Height; y++)
			{
				memcpy(dst, src, pitch);
				src += ms.RowPitch;
				dst += pitch;
			}
		}

		_context->Unmap(tex, 0);

		// 이미지로 만들자
		img = kobj_new(qgImage, std.Width, std.Height, QGCF32_BGRA, data, size);
	}

	// 정리
	tex->Release();
	scr->Release();

	return img;
}

//
qgTexture* D11Device::_RoamImplTexture(const qgArprTexture& ap)
{
	if (K_OFLAG(ap.flags, QGTEXF_OFF))
	{
		D11TextureOff* off = kobj_create(D11TextureOff);

		if (!off->_InitProperty(ap.type, ap.name, ap.width, ap.height, ap.depth, ap.mips, ap.flags, ap.fmt, this) ||
			!off->_CreateTexture(NULL, this) ||
			!off->_CreateOff(this))
		{
			off->Unload();
			off = NULL;
		}

		return off;
	}
	else
	{
		D11Texture* tex = kobj_create(D11Texture);

		if (!tex->_InitProperty(ap.type, ap.name, ap.width, ap.height, ap.depth, ap.mips, ap.flags, ap.fmt, this) ||
			!tex->_CreateTexture(NULL, this))
		{
			tex->Unload();
			tex = NULL;
		}

		return tex;
	}
}

//
qgTexture* D11Device::_RoamImplTexture(const qgArprImage& ap)
{
	D11Texture* tex = kobj_create(D11Texture);
	qgImage* img = ap.img;

	if (!tex->_InitImage(ap.name, img, 0, ap.flags, this) ||
		!tex->_CreateTexture(img, this))
	{
		tex->Unload();
		tex = NULL;
	}

	return tex;
}

//
qgTexture* D11Device::_RoamImplMotionTexture(const char* filename, kint flags)
{
	D11TextureMotion* tex = kobj_create(D11TextureMotion);

	if (!tex->_CreateMotion(filename, flags, this))
	{
		tex->Unload();
		tex = NULL;
	}

	return tex;
}

//
qgDepthBuffer* D11Device::_RoamImplDepthBuffer(const tpl::Point& size)
{
	D11DepthBuffer* buf = kobj_create(D11DepthBuffer);

	if (!buf->_Create(size.width, size.height, this))
	{
		buf->Unload();
		buf = NULL;
	}

	return buf;
}


//////////////////////////////////////////////////////////////////////////
// 텍스쳐
KIMPL_SUBCLASS(D11Texture, "D11Texture");

//
D11Texture::D11Texture() throw()
{
}

//
D11Texture::~D11Texture() throw()
{
	if (_node_desc)
	{
		ID3D11ShaderResourceView* srv = (ID3D11ShaderResourceView*)_node_desc;
		srv->Release();
	}

	kunk_release(_dev_tex);
	kobj_unload(_img_rsw);
	kobj_unload(_img_mip);
}

//
bool D11Texture::_InitImage(const char* name, qgImage* img, kint mips, kint flags, D11Device* dev)
{
	kint width = img->GetWidth();
	kint height = img->GetHeight();
	kint depth = 1;
	qgColorFormat fmt = img->GetColorFormat();

	return _InitProperty(QGTEXTURE_2D, name, width, height, depth, mips, flags, fmt, dev);
}

//
bool D11Texture::_InitProperty(qgTextureType type, const char* name, kint width, kint height, kint depth, kint mips, kint flags, qgColorFormat fmt, D11Device* dev)
{
	_key = name ? k_strdup(name) : k_apsprintf("d11_texture_%Lu", k_nth());
	_textype = type;
	_flags = flags;
	_mips = mips;
	_fmt = fmt == QGCF_NONE ? QGCF32_BGRA : fmt;

	// 포맷 맞춤
	_dev_fmt = D11Convert::DetectColor(_fmt, _alpha);
	if (_dev_fmt == DXGI_FORMAT_UNKNOWN)
	{
		// 지원하지 못하는 포맷
		return false;
	}

	if (K_OFLAG(flags, QGRESF_DYNAMIC))
	{
		if (K_OFLAG(flags, QGTEXF_OFF))
		{
			// 다이나믹 + 오프 금지
			return false;
		}

		if (!K_OFLAG(flags, QGTEXF_NOMIP))
		{
			// 다이나믹 -> 밉맵 금지
			K_YFLAG(_flags, QGTEXF_NOMIP, true);
		}

		_mips = 1;
		_dev_slp.Count = 1;
		_dev_slp.Quality = 0;
	}
	else
	{
		if (K_OFLAG(flags, QGTEXF_OFF))
		{
			if (!K_OFLAG(flags, QGTEXF_NOMIP))
			{
				// 오프 -> 밉맵 금지
				K_YFLAG(_flags, QGTEXF_NOMIP, true);
			}

			K_YFLAG(_insts, QGTEXI_OFF, true);
			_mips = 1;
			_dev_slp.Count = dev->GetMsaaCount();
			_dev_slp.Quality = dev->GetMsaaQuality();
		}
		else
		{
			if (!K_OFLAG(flags, QGTEXF_NOMIP))
			{
				// 오토 밉맵 지원하는 포맷인지 검사
				UINT supp = 0;
				if (SUCCEEDED(dev->GetDevice()->CheckFormatSupport(_dev_fmt, &supp)) &&
					(supp & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN))
				{
					K_YFLAG(_insts, QGTEXI_AUTOMIP, true);
					_mips = 0;
				}
				else
				{
					// 수동 밉맵은 지원안하니깐 밉맵은 1개
					_mips = 1;
				}
			}
			else
			{
				if (_mips == 0)
					_mips = 1;
			}

			_dev_slp.Count = 1;
			_dev_slp.Quality = 0;
		}
	}

	// 최대 크기로 맞춤
	kint maxsize = dev->GetCaps().max_texture_dimension;

	if (width < maxsize)
		_width = width;
	else
	{
		_width = maxsize;
		K_YFLAG(_insts, QGTEXI_CLAMP, true);
	}

	if (height < maxsize)
		_height = height;
	else
	{
		_height = maxsize;
		K_YFLAG(_insts, QGTEXI_CLAMP, true);
	}

	if (depth < maxsize)
		_depth = depth;
	else
	{
		_depth = maxsize;
		K_YFLAG(_insts, QGTEXI_CLAMP, true);
	}

	// D11은 언제나 정방이 아니어도 됨. 정방 맞추기는 GL쪽 참조
	// 그래서 _a... 변수 -> actual 변수가 없음

	if (K_OFLAG(flags, QGTEXF_MOTION))
		K_YFLAG(_insts, QGTEXI_MOTION, true);

	return true;
}

//
bool D11Texture::_CreateInternal(ID3D11ShaderResourceView** psrv, ID3D11Resource** pres, D3D11_SUBRESOURCE_DATA* subd, D11Device* dev)
{
	ID3D11Device* device = dev->GetDevice();

	UINT mlvtex, mlvsrv;
	UINT fbind, fcpu, fmisc;
	D3D11_USAGE usage;

	D3D11_TEXTURE1D_DESC dt1;
	D3D11_TEXTURE2D_DESC dt2;
	D3D11_TEXTURE3D_DESC dt3;
	D3D11_SHADER_RESOURCE_VIEW_DESC srvd;

	// 밉맵 개수 미리 맏져두고
	if (K_OFLAG(_insts, QGTEXI_AUTOMIP))
	{
		mlvtex = 0;
		mlvsrv = (UINT)-1;
	}
	else
	{
		mlvtex = _mips;
		mlvsrv = _mips;
	}

	// 바인드 스타일 만들기
	if (K_OFLAG(_flags, QGRESF_DYNAMIC))
	{
		usage = D3D11_USAGE_DYNAMIC;
		fbind = D3D11_BIND_SHADER_RESOURCE;
		fcpu = D3D11_CPU_ACCESS_WRITE;
		fmisc = 0;
	}
	else
	{
		usage = D3D11_USAGE_DEFAULT;
		fcpu = 0;
		fmisc = 0;

		// 오프 또는 오토밉?
		if (K_OFLAG(_insts, QGTEXI_OFF))
			fbind = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
		else
		{
			if (K_OFLAG(_insts, QGTEXI_AUTOMIP) == 0)
				fbind = D3D11_BIND_SHADER_RESOURCE;
			else
			{
				fbind = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
				fmisc = D3D11_RESOURCE_MISC_GENERATE_MIPS;
			}
		}
	}

	// 텍스쳐 만들기
	switch (_textype)
	{
		case QGTEXTURE_1D:	// 1D 텍스쳐 만들기
			// 텍스쳐 만들고
			dt1.Width = _width;
			dt1.MipLevels = mlvtex;
			dt1.ArraySize = 1;	// 배열 지원안함
			dt1.Format = _dev_fmt;
			dt1.Usage = usage;
			dt1.BindFlags = fbind;
			dt1.CPUAccessFlags = fcpu;
			dt1.MiscFlags = fmisc;

			if (FAILED(device->CreateTexture1D(&dt1, subd, (ID3D11Texture1D**)pres)))
			{
				kobj_tracep(KLV_ERROR, KERR_FAIL_CREATE);
				return false;
			}

			if (_mips == 0)
			{
				D3D11_TEXTURE1D_DESC tmp;
				(*(ID3D11Texture1D**)pres)->GetDesc(&tmp);
				_mips = tmp.MipLevels;
			}

			// 세이더 리소스 뷰 만들기
			srvd.Format = _dev_fmt;
			srvd.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D;
			srvd.Texture1D.MostDetailedMip = 0;
			srvd.Texture1D.MipLevels = mlvsrv;

			break;

		case QGTEXTURE_2D:	// 2D 텍스쳐 만들기
		case QGTEXTURE_CUBE:
			// 텍스쳐 만들기
			dt2.Width = _width;
			dt2.Height = _height;
			dt2.MipLevels = mlvtex;
			dt2.Format = _dev_fmt;
			dt2.SampleDesc = _dev_slp;
			dt2.Usage = usage;
			dt2.BindFlags = fbind;
			dt2.CPUAccessFlags = fcpu;
			dt2.MiscFlags = fmisc;

			if (_textype == QGTEXTURE_2D)
				dt2.ArraySize = _depth;
			else
			{
				dt2.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
				dt2.ArraySize = 6;
			}

			if (FAILED(device->CreateTexture2D(&dt2, subd, (ID3D11Texture2D**)pres)))
			{
				kobj_tracep(KLV_ERROR, KERR_FAIL_CREATE);
				return false;
			}

			if (_mips == 0)
			{
				D3D11_TEXTURE2D_DESC tmp;
				(*(ID3D11Texture2D**)pres)->GetDesc(&tmp);
				_mips = tmp.MipLevels;
			}

			// 세이더 리소스 뷰 만들기
			srvd.Format = _dev_fmt;

			if (_textype == QGTEXTURE_2D)
			{
				// 2D일때
				if (_dev_slp.Count > 1)
				{
					// MSAA가 달린 텍스쳐 = 오프 텍스쳐
					srvd.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DMS;
				}
				else
				{
					srvd.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;
					srvd.Texture2D.MostDetailedMip = 0;
					srvd.Texture2D.MipLevels = mlvsrv;
				}
			}
			else
			{
				// 큐브일때
				srvd.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE;
				srvd.TextureCube.MostDetailedMip = 0;
				srvd.TextureCube.MipLevels = mlvsrv;
			}

			break;

		case QGTEXTURE_3D:	// 3D 텍스쳐 만들기
			// 텍스쳐 만들고
			dt3.Width = _width;
			dt3.Height = _height;
			dt3.Depth = _depth;
			dt3.MipLevels = mlvtex;
			dt3.Format = _dev_fmt;
			dt3.Usage = usage;
			dt3.BindFlags = fbind;
			dt3.CPUAccessFlags = fcpu;
			dt3.MiscFlags = fmisc;

			if (FAILED(device->CreateTexture3D(&dt3, subd, (ID3D11Texture3D**)pres)))
			{
				kobj_tracep(KLV_ERROR, KERR_FAIL_CREATE);
				return false;
			}

			if (_mips == 0)
			{
				D3D11_TEXTURE3D_DESC tmp;
				(*(ID3D11Texture3D**)pres)->GetDesc(&tmp);
				_mips = tmp.MipLevels;
			}

			// 세이더 리소스 뷰 만들기
			srvd.Format = _dev_fmt;
			srvd.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D;
			srvd.Texture3D.MostDetailedMip = 0;
			srvd.Texture3D.MipLevels = mlvsrv;

		default:
			// 머임
			return false;
	}

	// 리소스 만들기
	if (FAILED(device->CreateShaderResourceView(*pres, &srvd, psrv)))
	{
		kobj_tracep(KLV_ERROR, KERR_FAIL_CREATE);
		(*pres)->Release();
		return false;
	}

	return true;
}

//
bool D11Texture::_CreateTexture(qgImage* img, D11Device* dev)
{
	ID3D11Resource* tex;
	ID3D11ShaderResourceView* srv;

	if (!img)
	{
		// 빈 텍스쳐 만들기
		if (!_CreateInternal(&srv, &tex, NULL, dev))
			return false;
	}
	else
	{
		// 이미지 처리
		if (K_OFLAG(_insts, QGTEXI_ADJPOW2 | QGTEXI_CLAMP) == 0)
		{
			// D11은 BGRA로 읽기 때문에 걍 씀
			_img_rsw = img;
			img->Load();
		}
		else
		{
			_img_rsw = kobj_new(qgImage, _width, _height, _fmt);
			img->CopyToScale(_img_rsw);
		}

		// 텍스쳐 만들기
		if (K_OFLAG(_insts, QGTEXI_AUTOMIP))
		{
			if (!_CreateInternal(&srv, &tex, NULL, dev))
				return false;

			// 여기 원래 잠궈야함
			D11Device* dev = (D11Device*)_dev;
			ID3D11DeviceContext* context = dev->GetContext();

			context->UpdateSubresource(tex, 0, NULL,
				_img_rsw->GetData(), _img_rsw->GetPitch(), _img_rsw->GetSize());
			context->GenerateMips(srv);
		}
		else
		{
			D3D11_SUBRESOURCE_DATA sd;
			sd.pSysMem = _img_rsw->GetData();
			sd.SysMemPitch = _img_rsw->GetPitch();
			sd.SysMemSlicePitch = _img_rsw->GetSize();

			if (!_CreateInternal(&srv, &tex, &sd, dev))
				return false;
		}
	}

	// 오케
	_dev_tex = tex;
	_node_desc = K_CAST_PTR_TO_PUINT(srv);

	return true;
}

//
bool D11Texture::EnterMap(qgTextureMap* map, kint flag, kint mips, qgTextureFace face)
{
	k_return_value_if_fail(map, false);
	k_return_value_if_fail(_lock_mip < 0, false);
	k_return_value_if_fail(_dev_tex, false);

	if ((kuint)mips >= _mips)
	{
		kobj_tracep(KLV_ERROR, KERR_OVERFLOW);
		return false;
	}

	// 다이나믹이면 그냥 잠근 내용을 보내자, 어짜피 WDONLY다.
	if (K_OFLAG(_flags, QGRESF_DYNAMIC))
	{
		ID3D11DeviceContext* context = ((D11Device*)_dev)->GetContext();

		// D3D11CalcSubresource(밉맵 번호, 면 번호, 총 밉맵개수)
		UINT cs = D3D11CalcSubresource(mips, face, _mips);
		D3D11_MAP flag = D3D11_MAP_WRITE_DISCARD;
		D3D11_MAPPED_SUBRESOURCE ms;

		if (FAILED(context->Map(_dev_tex, cs, flag, 0, &ms)))
			return false;

		// 정리
		map->data = (kbyte*)ms.pData;
		map->pitch = (kint)ms.RowPitch;
		map->slice = (kint)ms.DepthPitch;

		map->width = _width;
		map->height = _height;
		map->depth = _depth;
	}
	else
	{
		qgImage* img = _img_rsw;

		// 이미지가 없으면 만들기... 오프 포함. 참고로 오프는 다이나믹일 수 없다.
		if (!img || K_OFLAG(_insts, QGTEXI_OFF))
		{
			if (!img)
			{
				if (mips == 0)
					img = _img_rsw = kobj_new(qgImage, _width, _height, _fmt);
				else
				{
					int i = 0, w = _width, h = _height;

					do
					{
						if (w > 1)
							w >>= 1;

						if (h > 1)
							h >>= 1;
					} while (i != mips);

					img = _img_mip = kobj_new(qgImage, w, h, _fmt);
				}
			}

			// 이미지 다운로드... 하지 말자 귀찮다
			if (flag == QGENTF_READ || flag == QGENTF_READWRITE)
			{
				// 그래도 모르니 ScreenCapture() 함수를 참고로 만들면 된다
			}
		}

		// 정리
		map->data = img->GetData();
		map->pitch = img->GetPitch();
		map->slice = 0;

		map->width = img->GetWidth();
		map->height = img->GetHeight();
		map->depth = 0;
	}

	// 저장
	_lock_mip = mips;
	_lock_face = face;

	return true;
}

//
bool D11Texture::LeaveMap()
{
	k_return_value_if_fail(_lock_mip >= 0, false);

	// 
	ID3D11DeviceContext* context = ((D11Device*)_dev)->GetContext();

	// D3D11CalcSubresource(밉맵 번호, 면 번호, 총 밉맵개수)
	UINT cs = D3D11CalcSubresource(_lock_mip, _lock_face, _mips);

	// 다이나믹이면 그냥 품
	if (K_OFLAG(_flags, QGRESF_DYNAMIC))
	{
		// 딸랑 이거 하나임
		context->Unmap(_dev_tex, cs);
	}
	else
	{
		// 그냥? 아님 밉맵?
		qgImage* img = _img_mip ? _img_mip : _img_rsw;
		k_return_value_if_fail(img, false);

		// 압축 텍스쳐는 좀 다르다더라
		const qgPixelProp& prop = img->GetPixelProp();
		UINT pitch;

		if ((prop.flags&QGCFF_COMPRESS) == 0)
			pitch = img->GetPitch();
		else
		{
			if (prop.fmt == QGCF_DXT1)
				pitch = (img->GetWidth() / 4) * 8;
			else
				pitch = (img->GetWidth() / 4) * 16;
		}

		// 올리고
		D3D11_BOX dbox =
		{
			// left, top, front
			0, 0, 0,
			// right, bottom, back
			img->GetWidth(), img->GetHeight(), 1
		};
		context->UpdateSubresource(_dev_tex, cs, &dbox, img->GetData(), pitch, 0);

		// 자동 밉맵
		if (K_OFLAG(_insts, QGTEXI_AUTOMIP))
		{
			ID3D11ShaderResourceView* srv = (ID3D11ShaderResourceView*)_node_desc;
			context->GenerateMips(srv);
		}

		// 안쓰는 이미지 처리
		if (_img_mip)
		{
			_img_mip->Unload();
			_img_mip = NULL;
		}
		else if (!K_OFLAG(_flags, QGTEXF_IMAGE))
		{
			_img_rsw->Unload();
			_img_rsw = NULL;
		}
	}

	// 정리
	_lock_mip = -1;
	_lock_face = QGTXFX_NONE;

	return true;
}


//////////////////////////////////////////////////////////////////////////
// 모션 텍스쳐
KIMPL_SUBCLASS(D11TextureMotion, "D11TextureMotion");

//
D11TextureMotion::D11TextureMotion() throw()
{
}

//
D11TextureMotion::~D11TextureMotion() throw()
{
	// 렌더러 마다 텍스쳐 해제가 다르므로 여기서 함
	if (_mt_preimgs.IsEmpty())
		CleanStreams();
	else
	{
		kForEach(kuintptr n, _mt_preimgs)
		{
			ID3D11ShaderResourceView* srv = (ID3D11ShaderResourceView*)n;
			srv->Release();
		}
	}
}

//
qgITextureMotion* D11TextureMotion::GetMotion()
{
	return this;
}

//
bool D11TextureMotion::MotionUpdate(float adv)
{
	k_return_value_if_fail(_lock_mip < 0, false);

	//
	kuintptr ptr;
	bool res;

	if (!ManualUpdate(adv, res, ptr))
		return false;

	if (res)
	{
		// 다이나믹이므로 걍 처리
		qgTextureMap tm;
		if (D11Texture::EnterMap(&tm, 0, 0, QGTXFX_NONE))
		{
			qgImage* img = _mt_ucmimage;

			if (img->GetPitch() == tm.pitch)
				memcpy(tm.data, img->GetData(), img->GetSize());
			else
			{
				// 피치는 각 대상의 크기 단위라는 거 주의
				// 무조건 32비트 RGBA만 가능함
				qgCcmWork::COPY_32_32(_width, _height,
					(kint*)img->GetData(), 0, (kint*)tm.data, tm.pitch / 4, false);
			}

			D11Texture::LeaveMap();
		}
	}
	else if (ptr != 0)
	{
		if (ptr != _node_desc)
		{
			ID3D11ShaderResourceView* srv;

			if (_node_desc)
			{
				srv = (ID3D11ShaderResourceView*)_node_desc;
				srv->Release();
			}

			_node_desc = ptr;

			if (ptr)
			{
				srv = (ID3D11ShaderResourceView*)ptr;
				srv->AddRef();
			}
		}
	}

	return true;
}

//
bool D11TextureMotion::_CreateMotion(const char* filename, kint flags, D11Device* dev)
{
	// 스트림
	kStream* stm = dev->FileOpen(filename, true);
	if (stm == NULL)
		return NULL;

	if (!qgFwSupp::CheckHeadAndTail(stm))
	{
		stm->Unload();
		return NULL;
	}

	// 모션
	if (!ParseMotion(stm, K_OFLAG(flags, QGTEXF_PRELOAD)))
		return false;

	// 여기에서 쓴 색깔 포맷은 윈도우8 전용이다!!! 
	// DXGI 1.1 -> 1.0으로 하려면 RGBA를 BGRA로 고쳐야함
	qgImage* img = _mt_ucmimage;

	if (_mt_preimgs.IsEmpty())
	{
		// 한장 갖다 잠궈 씀
		if (!_InitProperty(QGTEXTURE_2D, filename, img->GetWidth(), img->GetHeight(), 1, 1, QGTEXF_S2D | QGRESF_DYNAMIC | QGTEXF_MOTION, QGCF32_RGBA, dev) ||
			!_CreateTexture(NULL, dev))
			return false;
	}
	else
	{
		// 모두 만들어 놓기
		if (!_InitProperty(QGTEXTURE_2D, filename, img->GetWidth(), img->GetHeight(), 1, 1, QGTEXF_S2D | QGTEXF_MOTION, QGCF32_RGBA, dev))
			return false;

		ID3D11ShaderResourceView* srv;
		ID3D11Resource* res;

		D3D11_SUBRESOURCE_DATA subd;
		subd.pSysMem = img->GetData();
		subd.SysMemPitch = img->GetPitch();
		subd.SysMemSlicePitch = img->GetSize();

		for (kuint i = 0; i < _mt_count; i++)
		{
			if (!UpdateStreamImage(i))
				srv = NULL;
			else
			{
				if (_CreateInternal(&srv, &res, &subd, dev))
					res->Release();
				else
				{
					// 오류 난 프레임만 패스
					srv = NULL;
				}
			}

			_mt_preimgs[i] = (kuintptr)srv;
		}

		// 0번 넣어 둠
		srv = (ID3D11ShaderResourceView*)_mt_preimgs[0];
		kunk_add_ref(srv);

		_node_desc = (kuintptr)srv;

		// 정리
		CleanStreams();

		K_YFLAG(_insts, QGTEXI_LIST, true);
	}

	// 오케
	return true;
}


//////////////////////////////////////////////////////////////////////////
// 오프 텍스쳐
KIMPL_SUBCLASS(D11TextureOff, "D11TextureOff");

//
D11TextureOff::D11TextureOff() throw()
{
}

//
D11TextureOff::~D11TextureOff() throw()
{
	if (_rtv)
		_rtv->Release();

	if (_db)
		_db->Unload();
}

//
qgITextureOff* D11TextureOff::GetOff()
{
	return this;
}

//
bool D11TextureOff::_CreateOff(D11Device* dev)
{
	ID3D11ShaderResourceView* srv = (ID3D11ShaderResourceView*)_node_desc;
	D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc;
	srv->GetDesc(&srvdesc);

	// 렌더 타깃 뷰
	D3D11_RENDER_TARGET_VIEW_DESC rtvdesc;
	memset(&rtvdesc, 0, sizeof(D3D11_RENDER_TARGET_VIEW_DESC));
	rtvdesc.Format = _dev_fmt;

	switch (srvdesc.ViewDimension)
	{
		case D3D_SRV_DIMENSION_BUFFER:
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_BUFFER;
			break;

		case D3D_SRV_DIMENSION_TEXTURE1D:
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D;
			break;

		case D3D_SRV_DIMENSION_TEXTURE2D:
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
			break;

		case D3D_SRV_DIMENSION_TEXTURE2DMS:
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
			break;

		case D3D_SRV_DIMENSION_TEXTURE3D:
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
			break;

#if 0
		case D3D_SRV_DIMENSION_TEXTURECUBE:
			// 아직 준비 못함. 사용 금지
			rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
			rtvdesc.Texture2DArray.FirstArraySlice = (FACE번호 넣어야함);
			rtvdesc.Texture2DArray.ArraySize = 1;
			rtvdesc.Texture2DArray.MipSlice = 0;
			break;
#endif

		default:
			return false;
	}

	ID3D11RenderTargetView* rtv;
	HRESULT hr = dev->GetDevice()->CreateRenderTargetView(_dev_tex, &rtvdesc, &rtv);

	if (FAILED(hr))
		return false;

	//
	_rtv = rtv;

	return true;
}

bool D11TextureOff::EnterOff(kint clearance, const tpl::ColorValue& color)
{
	if (K_OFLAG(_insts, QGTEXI_LOCKOFF))
		return false;

	// 깊이 버퍼
	D11DepthBuffer* db = _db;
	if (db == NULL)
		_db = db = (D11DepthBuffer*)_dev->CreateDepthBuffer(_width, _height);

	// 설정
	_dev->_SetRenderTarget(this);

	D3D11_VIEWPORT vp;
	vp.TopLeftX = 0.0f;
	vp.TopLeftY = 0.0f;
	vp.Width = (float)_width;
	vp.Height = (float)_height;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;

	ID3D11DeviceContext* context = ((D11Device*)_dev)->GetContext();
	ID3D11DepthStencilView* dsv = db ? (ID3D11DepthStencilView*)db->GetDescription() : NULL;

	context->OMSetRenderTargets(1, &_rtv, dsv);
	context->RSSetViewports(1, &vp);

	// 클리어
	if (clearance&QGCLEAR_RENDER)
		context->ClearRenderTargetView(_rtv, tpl::Color(color).ToPointer());

	if (clearance&(QGCLEAR_DEPTH | QGCLEAR_STENCIL))
	{
		UINT u = clearance&(D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL);
		context->ClearDepthStencilView(dsv, u, 1.0f, 0);
	}

	// 올ㅋ
	K_YFLAG(_insts, QGTEXI_LOCKOFF, true);

	return true;
}

bool D11TextureOff::LeaveOff()
{
	if (!K_OFLAG(_insts, QGTEXI_LOCKOFF))
		return false;

	_dev->_SetRenderTarget(NULL);

	K_YFLAG(_insts, QGTEXI_LOCKOFF, false);

	return true;
}


//////////////////////////////////////////////////////////////////////////
// 뎁스 버퍼
KIMPL_SUBCLASS(D11DepthBuffer, "D11DepthBuffer");

//
D11DepthBuffer::D11DepthBuffer() throw()
{
}

//
D11DepthBuffer::~D11DepthBuffer() throw()
{
	ID3D11DepthStencilView* dsv = (ID3D11DepthStencilView*)_node_desc;
	kunk_release(dsv);
}

//
bool D11DepthBuffer::_Create(kuint width, kuint height, D11Device* dev)
{
	ID3D11Device* device = dev->GetDevice();
	HRESULT hr;

	// DXGI_FORMAT_D24_UNORM_S8_UINT - 32비트 24깊이 8스텐실
	// DXGI_FORMAT_D32_FLOAT - 32비트 깊이
	// DXGI_FORMAT_D32_FLOAT_S8X24_UINT - 64비트? 32깊이 8스텐실 24안씀

	D3D11_TEXTURE2D_DESC texdesc;
	texdesc.Width = width;
	texdesc.Height = height;
	texdesc.MipLevels = 1;
	texdesc.ArraySize = 1;	// 큐브 지원안함 오직 평평
	texdesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	texdesc.SampleDesc.Count = dev->GetMsaaCount();
	texdesc.SampleDesc.Quality = dev->GetMsaaQuality();
	texdesc.Usage = D3D11_USAGE_DEFAULT;
	texdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	texdesc.CPUAccessFlags = 0;
	texdesc.MiscFlags = 0;	// 큐브 지원안함 (D3D11_RESOURCE_MISC_TEXTURECUBE)

	ID3D11Texture2D* dstex;
	hr = device->CreateTexture2D(&texdesc, NULL, &dstex);

	if (FAILED(hr))
		return false;

	D3D11_DEPTH_STENCIL_VIEW_DESC dsvdesc;
	memset(&dsvdesc, 0, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
	dsvdesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	dsvdesc.ViewDimension = (texdesc.SampleDesc.Count > 1) ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;

	ID3D11DepthStencilView* dsv;
	hr = device->CreateDepthStencilView(dstex, &dsvdesc, &dsv);

	dstex->Release();	// 이걸 놔두면 나중에 그릴 수 있을까?

	if (FAILED(hr))
		return false;

	//
	_node_desc = K_CAST_PTR_TO_PUINT(dsv);
	_width = width;
	_height = height;

	return true;
}

#endif	// _QG_USE_D11

